package com.leyou.item.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.vo.PageResult;
import com.leyou.item.dto.*;
import com.leyou.item.entity.Sku;
import com.leyou.item.entity.Spu;
import com.leyou.item.entity.SpuDetail;
import com.leyou.item.mapper.SkuMapper;
import com.leyou.item.mapper.SpuDetailMapper;
import com.leyou.item.mapper.SpuMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.leyou.common.constants.MQConstants.Exchange.ITEM_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKey.ITEM_DOWN_KEY;
import static com.leyou.common.constants.MQConstants.RoutingKey.ITEM_UP_KEY;

@Service
@Slf4j
public class GoodsService {

    @Autowired
    private SpuMapper spuMapper;


    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SpuDetailMapper spuDetailMapper;

    @Autowired
    private SkuMapper skuMapper;


    public PageResult<SpuDTO> pageQuery(Integer page, Integer rows, String key, Boolean saleable) {
        PageHelper.startPage(page, rows);


        Example example = new Example(Spu.class);

        Example.Criteria criteria = example.createCriteria();

        //where saleable = 1
        if (null != saleable) {
            criteria.andEqualTo("saleable", saleable);
        }

        //条件拼接
        if (StringUtils.isNotBlank(key)) {
            criteria.andLike("name", "%" + key + "%");
        }


        //根据条件查询
        List<Spu> spuList = this.spuMapper.selectByExample(example);

        if (CollectionUtils.isEmpty(spuList)) {
            throw new LyException(ExceptionEnum.DATA_NOT_FOUND);
        }

        PageInfo<Spu> pageInfo = new PageInfo<>(spuList);

        List<SpuDTO> spuDTOS = BeanHelper.copyWithCollection(spuList, SpuDTO.class);

        spuDTOS.forEach(spuDTO -> {

            BrandDTO brandDTO = this.brandService.queryBrandById(spuDTO.getBrandId());

            spuDTO.setBrandName(brandDTO.getName());


            List<CategoryDTO> categoryDTOS = this.categoryService.queryCategoryByIds(spuDTO.getCategoryIds());


            //通过stream流，从集合中获取到每个对象，然后，取出其名称，并把名称拼接为字符串，拼接的分隔符为/
            String names = categoryDTOS.stream().map(CategoryDTO::getName).collect(Collectors.joining("/"));

            //把数组集合，拼接成字符串，拼接时可以设定，分隔符
            spuDTO.setCategoryName(names);

        });

        return new PageResult<>(pageInfo.getTotal(), pageInfo.getPages(), spuDTOS);
    }


    //TODO 新增商品时也要做索引的创建，以及静态页创建
    @Transactional
    public void addGoods(SpuDTO spuDTO) {
        Spu spu = BeanHelper.copyProperties(spuDTO, Spu.class);

        spu.setCreateTime(new Date());
        spu.setUpdateTime(spu.getCreateTime());

        //保存spu并返回spuId
        int count = this.spuMapper.insertSelective(spu);

        if (1 != count) {
            throw new LyException(ExceptionEnum.DATA_SAVE_ERROR);
        }

        //保存spuDetail
        SpuDetail spuDetail = BeanHelper.copyProperties(spuDTO.getSpuDetail(), SpuDetail.class);
        spuDetail.setSpuId(spu.getId());
        spuDetail.setCreateTime(spu.getCreateTime());
        spuDetail.setUpdateTime(spu.getCreateTime());

        try {
            count = this.spuDetailMapper.insertSelective(spuDetail);
            log.info("【商品服务】spu保存成功");
        } catch (Exception e) {
            log.error("【商品服务】spu保存失败，数据库操作失败");
            e.printStackTrace();
        }

        if (1 != count) {
            log.error("【商品服务】spu保存失败，数据库操作失败");
            throw new LyException(ExceptionEnum.DATA_SAVE_ERROR);
        }

        //保存sku,List<SkuDTO>====>List<Sku>

//        List<Sku> skus = BeanHelper.copyWithCollection(spuDTO.getSkus(), Sku.class);
//
//        skus.forEach(sku -> sku.setSpuId(spu.getId()));


        saveSku(spuDTO, spu);
    }

    public SpuDetailDTO querySpuDetailById(Long id) {
        //根据spu_id查询对应的spuDetail
        SpuDetail spuDetail = this.spuDetailMapper.selectByPrimaryKey(id);

        if (spuDetail == null) {
            throw new LyException(ExceptionEnum.DATA_NOT_FOUND);
        }
        return BeanHelper.copyProperties(spuDetail, SpuDetailDTO.class);
    }

    /**
     * 根据spuId查询对应的sku集合
     *
     * @param spuId
     * @return
     */
    public List<SkuDTO> querySkuBySpu(Long spuId) {

        Sku record = new Sku();
        record.setSpuId(spuId);

        List<Sku> skus = this.skuMapper.select(record);

        if (CollectionUtils.isEmpty(skus)) {
            throw new LyException(ExceptionEnum.DATA_NOT_FOUND);
        }
        return BeanHelper.copyWithCollection(skus, SkuDTO.class);
    }

    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        Spu spu = BeanHelper.copyProperties(spuDTO, Spu.class);

        spu.setUpdateTime(new Date());

        //修改spu
        int count = this.spuMapper.updateByPrimaryKeySelective(spu);

        if (1 != count) {
            throw new LyException(ExceptionEnum.DATA_MODIFY_ERROR);
        }

        //修改spuDetail

        SpuDetail spuDetail = BeanHelper.copyProperties(spuDTO.getSpuDetail(), SpuDetail.class);

        spuDetail.setUpdateTime(spu.getUpdateTime());
        count = this.spuDetailMapper.updateByPrimaryKeySelective(spuDetail);

        if (1 != count) {
            throw new LyException(ExceptionEnum.DATA_MODIFY_ERROR);
        }

        //sku修改

        //删除当前spu下所有的sku信息，然后重建sku关系
        Sku deleteRecord = new Sku();
        deleteRecord.setSpuId(spu.getId());

        count = this.skuMapper.selectCount(deleteRecord);

        //根据spuId删除sku
        int deleteCount = this.skuMapper.delete(deleteRecord);

        if (count != deleteCount) {
            throw new LyException(ExceptionEnum.DATA_MODIFY_ERROR);
        }
        //重建spu和sku关系

        saveSku(spuDTO, spu);
    }

    private void saveSku(SpuDTO spuDTO, Spu spu) {
        int count;
        List<Sku> skus = spuDTO.getSkus().stream().map(skuDTO -> {
            Sku sku = BeanHelper.copyProperties(skuDTO, Sku.class);
            sku.setSpuId(spu.getId());
            //createTime,updateTime,当sql为insertSelective时候，时间会自动匹配，
            sku.setCreateTime(spu.getUpdateTime());
            sku.setUpdateTime(spu.getUpdateTime());
            return sku;
        }).collect(Collectors.toList());

        count = this.skuMapper.insertList(skus);

        if (count != skus.size()) {
            throw new LyException(ExceptionEnum.DATA_SAVE_ERROR);
        }
    }

    /**
     * 上下架时，同时关联操作，search服务以及page服务
     * 引入search服务和page服务的interface，从而形成可以发起请求模式
     *
     * @param id
     * @param saleable
     */
    @Autowired
    private AmqpTemplate amqpTemplate;

    @Transactional
    public void modifySaleable(Long id, Boolean saleable) {

        Spu record = new Spu();

        record.setId(id);
        record.setSaleable(saleable);
        record.setUpdateTime(new Date());

        int count = this.spuMapper.updateByPrimaryKeySelective(record);

        if (1 != count) {
            throw new LyException(ExceptionEnum.DATA_MODIFY_ERROR);
        }

        //不仅要下架spu，spu对应的sku也要下架，上架同理

        this.skuMapper.updateSaleable(id, saleable, record.getUpdateTime());

        String key = saleable ? ITEM_UP_KEY : ITEM_DOWN_KEY;

        //发送三个参数，交换机名称，routingKey，消息内容，spuId
        this.amqpTemplate.convertAndSend(ITEM_EXCHANGE_NAME, key, id);

    }

    public SpuDTO querySpuById(Long id) {
        Spu spu = this.spuMapper.selectByPrimaryKey(id);
        if (null == spu) {
            throw new LyException(ExceptionEnum.DATA_NOT_FOUND);
        }
        return BeanHelper.copyProperties(spu, SpuDTO.class);
    }

    public List<SkuDTO> querySkuByIds(List<Long> ids) {
        List<Sku> skuList = skuMapper.selectByIdList(ids);
        if (CollectionUtils.isEmpty(skuList)) {
            throw new LyException(ExceptionEnum.DATA_NOT_FOUND);
        }
        return BeanHelper.copyWithCollection(skuList, SkuDTO.class);
    }

    /*@Autowired
    private SqlSessionFactory factory;

    public void deductStock(Map<Long, Integer> skuMap) {
        // 开启批处理
        SqlSession sqlSession = factory.openSession(ExecutorType.BATCH);
        try {
            // 遍历
            for (Map.Entry<Long, Integer> entry : skuMap.entrySet()) {
                // 组织参数
                Map<String,Object> params = new HashMap<>();
                params.put("id", entry.getKey());
                params.put("num", entry.getValue());
                // 编译Sql
                sqlSession.update("com.leyou.item.mapper.SkuMapper.deductStock", params);
            }
            // 执行Sql
            sqlSession.flushStatements();
            // 提交事务
            sqlSession.commit();

        } catch (Exception e) {
            // 异常就回滚
            sqlSession.rollback();
            // 减库存失败，库存不足
            throw new LyException(ExceptionEnum.STOCK_NOT_ENOUGH);
        } finally {
            // 关闭
            sqlSession.close();
        }
    }*/


    @Transactional
    public void deductStock(Map<Long, Integer> skuMap) {
        try {
            for (Map.Entry<Long, Integer> entry : skuMap.entrySet()) {
                skuMapper.deductStock(entry.getKey(), entry.getValue());
            }
        } catch (Exception e) {
            // 减库存失败，库存不足
            throw new LyException(ExceptionEnum.STOCK_NOT_ENOUGH);
        }
    }
}
